<template>
  <view class="container">
    <view class="initBox" @click="isInit = false" v-if="isInit">
      <view class="rectBox">
        <image
          class="rectRobot"
          src="@/static/images/aiGuidance/robot.png"
        ></image>
        <view class="rectContent">
          <view class="rectTitle"> 智能导诊 </view>
          提前描述自己的病情信息， 有效提升就诊体验。
        </view>
      </view>
    </view>
    <view class="listBox" v-if="!isInit" ref="messageListRef">
      <view
        v-for="(item, index) in messageList"
        :key="item.id"
        class="listItem"
        :class="[item.role === 1 ? 'end' : '']"
      >
        <view v-if="item.role === 1" class="question">
          {{ item.content }}
        </view>

        <view
          v-if="item.role === 2 && !item.content && !item.thinkContent"
          class="answer"
        >
          <view class="answerTitle">
            <image src="@/static/images/aiGuidance/robot-small.png"></image
            >智能导诊
          </view>
          <!-- <view class="animate-blink"></view> -->
          <view class="searchBox"
            ><svg
              t="1746512427724"
              class="icon"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="2309"
              width="30"
              height="30"
            >
              <path
                d="M991.418182 972.8L791.272727 772.654545c79.127273-83.781818 130.327273-195.490909 130.327273-316.50909 0-251.345455-200.145455-451.490909-446.836364-451.49091C232.727273 0 32.581818 204.8 32.581818 451.490909s200.145455 451.490909 446.836364 451.490909c97.745455 0 190.836364-32.581818 265.309091-88.436363l200.145454 204.8 46.545455-46.545455zM102.4 451.490909c0-209.454545 167.563636-381.672727 377.018182-381.672727s377.018182 172.218182 377.018182 381.672727-172.218182 386.327273-381.672728 386.327273c-204.8 0-372.363636-172.218182-372.363636-386.327273z"
                fill="#3f81f1"
                p-id="2310"
              ></path></svg
            >正在搜索相关资料...</view
          >
        </view>
        <view
          v-if="item.role === 2 && (item.content || item.thinkContent)"
          class="answer"
        >
          <view class="answerTitle">
            <image src="@/static/images/aiGuidance/robot-small.png"></image
            >智能导诊
          </view>
          <view class="pickerBox" v-if="item.age">
            {{ item.content }}
            <!-- <view class="flex">
							<picker class="picker" @change="ageChange" :disabled="age ? true : false" :value="age"
								:range="range">
								<view class="picker">
									{{ age ? age : "请选择" }}
								</view>
							</picker>
							<text style="margin-left: 20rpx;" class="lg text-gray cuIcon-right"></text>
						</view> -->
          </view>
          <view v-if="!item.age && item.status != 'recommendation'">
            <text class="gray">
              {{ item.thinkContent }}
            </text>
            <text v-if="item.content">
              {{ item.content }}
            </text>
          </view>
          <view v-if="!item.age && item.status == 'recommendation'">
            <text class="gray">
              {{ item.thinkContent }}
            </text>
            <view
              style="font-size: 32rpx; margin-top: 20px"
              class="m-b-10"
              v-if="item.content"
            >
              科室推荐：
            </view>

            <view
              class="item flex align-center p-t-5 p-b-5"
              @click="turnTo(item.keshi)"
              v-if="item.content"
            >
              <u--image
                width="35"
                height="35"
                :src="require('@/static/images/homeIndex/dept-ico.png')"
                shape="circle"
              ></u--image>
              <view
                style="flex: 1"
                class="flex flex-column justify-around p-l-16 p-t-10 p-b-10"
              >
                <view class="flex align-center justify-between m-b-10">
                  <view class="flex align-center">
                    <text
                      style="font-size: 32rpx; color: #323232"
                      class="m-r-20"
                      >{{ item.keshi }}</text
                    >
                  </view>
                  <img
                    style="width: 40rpx"
                    src="@/static/images/arrow-right.svg"
                    alt=""
                  />
                </view>
              </view>
            </view>
          </view>
        </view>
        <view
          v-if="
            item.role === 2 &&
            item.done &&
            item.card &&
            item.card.length > 0 &&
            index == messageList.length - 1
          "
          class="answerCardBox"
        >
          <view
            v-for="(card, indexx) in item.card"
            :key="indexx"
            class="answerCardItem"
            @click="cardClick(card)"
          >
            {{ card }}
          </view>
        </view>
        <view
          v-if="
            item.role === 2 &&
            item.done &&
            item.cardCopy &&
            item.cardCopy.length > 0 &&
            index == messageList.length - 1
          "
          class="answerCardBox"
        >
          <view
            v-for="(card, indexx) in item.cardCopy"
            :key="indexx"
            class="answerCardItem"
            @click="cardChange(item, indexx)"
          >
            {{ card.content }}
            <svg
              v-if="indexx == item.selected"
              t="1745991486194"
              class="icon"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="8372"
              width="300"
              height="300"
            >
              <path d="M0 1024h1024V0z" fill="#1296db" p-id="8373"></path>
              <path
                d="M896.5 531.7l-253.1 256L537.9 681l-42.2 42.7 113.6 114.9 34 34.4 295.4-298.7z"
                fill="#fff"
                p-id="8374"
              ></path>
            </svg>
          </view>
        </view>
      </view>
    </view>

    <view class="modalList" v-if="!isInit && modalList.length > 0">
      <view
        v-for="(card, indexx) in modalList"
        :key="indexx"
        class="modalListItem"
        :class="card.dictValue == modalUrl ? 'selected' : ''"
        @click="modalUrl = card.dictValue"
      >
        {{ card.dictLabel }}
      </view>
    </view>
    <view class="search-footer" v-if="!isInit">
      <input
        class="input"
        type="text"
        :disabled="loading || !gender"
        v-model="question"
        :placeholder="placeholder"
      />
      <button
        :disabled="loading || !gender"
        :class="loading || !gender ? 'disabled' : ''"
        class="button"
        @click="handleSubmit()"
      >
        发 送
      </button>
    </view>
  </view>
</template>

<script>
import { getModalList, confirmLLMSave } from "@/api/home/aiGuidance.js";
import config from "@/config";

import { getDeptList } from "@/api/home/home.js";
export default {
  data() {
    return {
      isInit: true,
      question: "",
      loading: false,
      messageList: [
        {
          id: uni.$u.guid(),
          role: 2,

          content: `是否允许自动获取您的个人信息？`,
          done: true,
          card: ["拒绝", "允许"],
        },
      ],
      modalList: [],
      modalUrl: "",
      modalUrlValue: config.modelUrl,
      /**身份证号 */
      idNum: "",
      /**健康卡号，一个身份证号能对应多个健康卡号 */
      cardNum: "",
      notAllowed: false,
      gender: "",
      age: null,
      isAgeInput: false,
      range: [],
      deptList: [],
      hospitalCode: "",
      session_id: "",
      placeholder: "",
    };
  },
  components: {},
  onLoad(option) {
    try {
      if (uni.getStorageSync("currentVisitCard")) {
        this.idNum = JSON.parse(uni.getStorageSync("currentVisitCard"))
          ? JSON.parse(uni.getStorageSync("currentVisitCard")).idNum
          : "";
        this.cardNum = JSON.parse(uni.getStorageSync("currentVisitCard"))
          ? JSON.parse(uni.getStorageSync("currentVisitCard")).cardNum
          : "";
      }
    } catch (error) {}

    getModalList().then((res) => {
      this.modalList = res.data;
      this.modalUrl = this.modalList[0].dictValue;
    });

    for (let i = 1; i < 120; i++) {
      this.range.push(i);
    }
    // TODO:
    let hosCode = uni.getStorageSync("hospital") || "";
    // let hosCode = `{"name":"沁阳市人民医院","hospitalCode":"01"}`;
    this.hospitalCode = JSON.parse(hosCode).hospitalCode;
    getDeptList({
      hospitalCode: this.hospitalCode,
      isShow: "1",
    }).then((res) => {
      this.deptList = res.rows;
    });
  },
  methods: {
    getInfoFromIdCard(idCard) {
      // 校验身份证长度（仅示例，实际需更完整校验）
      if (typeof idCard !== "string" || idCard.length !== 18) {
        throw new Error("身份证号格式错误");
      }
      // 提取关键字段
      const birthDateStr = idCard.slice(6, 14); // 出生年月日
      const genderCode = parseInt(idCard.charAt(16), 10); // 第17位（索引16）

      // 解析出生日期
      const year = parseInt(birthDateStr.slice(0, 4)),
        month = parseInt(birthDateStr.slice(4, 6)) - 1, // 月份从0开始
        day = parseInt(birthDateStr.slice(6, 8));
      const birthDate = new Date(year, month, day);
      // 校验日期合法性
      if (isNaN(birthDate.getTime())) {
        throw new Error("身份证出生日期无效");
      }
      // 计算年龄
      const today = new Date();
      let age = today.getFullYear() - birthDate.getFullYear();
      const monthDiff = today.getMonth() - birthDate.getMonth();
      if (
        monthDiff < 0 ||
        (monthDiff === 0 && today.getDate() < birthDate.getDate())
      ) {
        age--;
      }

      // 判断性别
      const gender = genderCode % 2 === 1 ? "男" : "女";
      return {
        gender,
        age,
      };
    },
    ageChange(e) {
      this.age = e.detail.value + 1;
    },
    cardClick(card) {
      if (card == "允许") {
        // 点了允许，如果获取身份证失败，就仍然需要用户自己去手动输入性别和年龄
        try {
          const info = this.getInfoFromIdCard(this.idNum);
          console.log(7777777, this.idNum, info);

          this.gender = info.gender;
          this.age = info.age;
          this.messageList.push(
            {
              id: uni.$u.guid(),
              role: 1,
              content: "允许",
            },
            {
              id: uni.$u.guid(),
              role: 2,
              content: `您好！请描述您的症状，我会帮您推荐合适的科室。`,
              done: false,
            }
          );
        } catch (error) {
          console.error("身份证解析错误:", error);
          this.loading = false;
          this.messageList.push({
            id: uni.$u.guid(),
            role: 2,
            content: `请选择您的性别`,
            done: true,
            card: ["男", "女"],
          });
        }
      } else if (card == "拒绝") {
        this.messageList.push({
          id: uni.$u.guid(),
          role: 2,

          content: `请选择您的性别`,
          done: true,
          card: ["男", "女"],
        });
      } else if (card == "男" || card == "女") {
        this.gender = card;

        this.messageList.push(
          {
            id: uni.$u.guid(),
            role: 1,
            content: card,
          },
          {
            id: uni.$u.guid(),
            role: 2,

            content: `请输入您的年龄`,
            done: true,
            age: true,
          }
        );
        this.isAgeInput = true;
      } else {
        this.handleSubmit(card);
      }
    },
    cardChange(item, indexx) {
      item.selected = indexx;
      //card.selected = !card.selected;
      this.$forceUpdate();
    },
    async scrollToBottom() {
      await this.$nextTick();
      if (this.$refs.messageListRef.$el) {
        this.$refs.messageListRef.$el.scrollTop =
          this.$refs.messageListRef.$el.scrollHeight;
      }
    },
    handleSubmit(data) {
      if (this.isAgeInput) {
        if (isNaN(this.question) || this.question < 1 || this.question > 150) {
          uni.showToast({
            title: "请输入正确年龄",
            icon: "error",
            mask: true,
          });
          this.question = "";
        } else {
          this.age = this.question;
          this.question = "";
          this.isAgeInput = false;
          this.messageList.push(
            {
              id: uni.$u.guid(),
              role: 1,
              content: this.age,
            },
            {
              id: uni.$u.guid(),
              role: 2,

              content: `您好！请描述您的症状，我会帮您推荐合适的科室。`,
              done: true,
            }
          );
        }
        return;
      }

      let msg;
      if (data) {
        msg = data;
      } else {
        if (
          this.messageList[this.messageList.length - 1].cardCopy &&
          this.messageList[this.messageList.length - 1].selected != undefined
        ) {
          // 如果有选中的卡片
          // 取出选中的卡片的内容，并拼接问题
          msg =
            this.messageList[this.messageList.length - 1].cardCopy[
              this.messageList[this.messageList.length - 1].selected
            ].content;
          if (this.question.trim() != "") {
            // 如果输入框有内容，拼接到选中的卡片后面
            msg = msg + "，" + this.question.trim();
          }
          this.question = "";
        } else {
          // 如果没有选中的卡片，直接使用输入框的内容
          // 这里可以添加一些验证逻辑，比如检查输入是否为空等
          if (this.question.trim() == "") {
            uni.showToast({
              title: "请输入问题",
              icon: "error",
              mask: true,
            });
            return;
          } else {
            msg = this.question.trim();
            this.question = "";
          }
        }
      }
      this.placeholder = "";
      this.loading = true;
      let msgId = uni.$u.guid();
      this.messageList.push({
        id: msgId + "_1",
        content: msg,
        role: 1,
      });
      this.messageList.push({
        id: msgId + "_2",
        content: undefined,
        role: 2,
      });
      this.scrollToBottom();

      const history = this.messageList
        .map((e) => {
          if (e.content) {
            return (e.role == 1 ? "患者:" : "导诊助手:") + e.content;
          }
          return undefined;
        })
        .filter(Boolean);
      history.unshift("患者：" + "性别" + this.gender + "年龄" + this.age);

      let that = this;

      this.fetchChatApi(
        {
          history,
          input: msg,
          model_name: this.modalUrl,
        },
        (res) => {
          try {
            const item = that.messageList[that.messageList.length - 1];
            item.status = res.status;
            if (res.session_id) {
              that.session_id = res.session_id;
            }
            // 如果是推荐科室
            if (item.status == "recommendation") {
              if (res.is_complete) {
                if (res.text.includes("</think>")) {
                  const arr = res.text.split("</think>");
                  item.thinkContent = arr[0];
                  item.keshi = arr[1].trim().replace(/^\s+/, "");
                } else {
                  item.thinkContent = res.text;
                }

                item.content = item.keshi;
                item.done = true;
                that.loading = false;
                that.confirmLLM(item.keshi).then((res) => {
                  confirmLLMSave({
                    ...res.medical_record,
                    cardNum: that.cardNum,
                    suggestion: item.keshi,
                  }).then((res) => {});
                });
              } else {
                if (res.text) {
                  if (res.text.includes("</think>")) {
                    const arr = res.text.split("</think>");
                    item.thinkContent = arr[0];
                    item.keshi = arr[1].trim().replace(/^\s+/, "");
                  } else {
                    item.thinkContent = res.text;
                  }
                }
              }
            } else {
              // 如果是普通的文本回答
              if (res.is_complete) {
                const lines = item.content.split("\n");
                let arr = lines.filter((line) => line.match(/^[a-z]\)/));

                item.cardCopy = arr.map((line) => {
                  return {
                    content: line.replace(/[a-zA-Z0-9]\)\s+/g, ""),
                    selected: false,
                  };
                });
                that.placeholder = "如有其他情况，请补充说明";

                item.done = true;
                that.loading = false;
              } else {
                if (res.text) {
                  if (res.text.includes("</think>")) {
                    const arr = res.text.split("</think>");

                    item.thinkContent = arr[0];
                    item.content = arr[1];
                  } else {
                    item.thinkContent = res.text;
                  }
                }
              }
            }
          } catch (error) {
            console.error("处理响应数据时出错:", error);
            that.loading = false;
            that.messageList[that.messageList.length - 1].content = "发生错误";
          }
          that.$forceUpdate();

          that.scrollToBottom();
        }
      );
    },

    fetchChatApi(opts = {}, cb = () => {}) {
      fetch(this.modalUrlValue + "/v1/sendIpc", {
        //fetch("http://192.168.10.121:5000/api/consult", {
        method: "POST",
        body: JSON.stringify(opts),
        headers: {
          Accept: "text/event-stream",
          "Content-Type": "application/json;charset=utf-8",
        },
      })
        .then((res) => {
          if (res.status !== 200) throw res;

          const reader = res.body?.getReader();

          const decoder = new TextDecoder();

          let buffer = ""; // 新增：用于累积未完成的字符串
          const readFn = () => {
            reader?.read().then(({ value, done }) => {
              if (value) {
                // 解码时保留未完成字节（关键！）
                const dstr = decoder.decode(value, {
                  stream: true,
                });
                buffer += dstr; // 累积到缓冲区

                // 尝试按分隔符（如换行符）分割处理
                const parts = buffer.split("\n");
                parts.slice(0, -1).forEach((part) => {
                  let data = {};
                  // 处理完整部分
                  try {
                    data = JSON.parse(part);
                  } catch (e) {
                    console.error("解析 JSON 失败:", part);
                  }
                  cb({
                    text: data.response?.trim(),
                    status: data.status,
                    session_id: data.session_id,
                    is_complete: data.is_complete,
                  });
                });
                // 保留未完成部分到缓冲区
                buffer = parts[parts.length - 1] || "";
              }
              if (!done) {
                readFn();
              } else {
                // 处理最终残留数据（若有）

                if (buffer) {
                  let data = {};

                  try {
                    data = JSON.parse(buffer);
                  } catch (e) {
                    console.error("最终解析失败:", buffer);

                    data.is_complete = true; // 标记为完成
                  }
                  cb({
                    text: data.response?.trim(),
                    status: data.status,
                    session_id: data.session_id,
                    is_complete: data.is_complete,
                  });
                }
                // 清空解码器缓冲区（关键！）
                decoder.decode();
              }
            });
          };
          readFn();
        })
        .catch((err) => {
          console.log("err: ", err);
          if (err?.name === "AbortError") {
            // 停止生成
            return;
          }
          cb({
            text: "服务器繁忙，请稍后重试",
            is_complete: true,
          });
        });
    },
    async turnTo(val) {
      console.log("要跳往的科室", val, this.deptList);
      const item = this.deptList.filter((e) => e.deptName == val)[0];
      console.log("筛选出来的科室", item);

      uni.navigateTo({
        url:
          "/pages/home/deptDetail?id=" +
          item.id +
          "&deptName=" +
          encodeURIComponent(item.deptName) +
          "&deptCode=" +
          item.deptCode,
      });
    },
    // 调用后端API
    async confirmLLM(recommended_department) {
      try {
        const history = this.messageList.map(
          (e) => (e.role == 1 ? "患者:" : "导诊助手:") + e.content
        );
        history.unshift("患者：" + "性别" + this.gender + "年龄" + this.age);

        const response = await fetch(this.modalUrlValue + "/v1/sendConfirm", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            history,
            recommended_department,
            session_id: this.session_id,
          }),
        });

        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}));
          const errorMessage = errorData.message || "服务器内部错误";
          throw new Error(
            `服务器响应错误: ${response.status} - ${errorMessage}`
          );
        }

        return await response.json();
      } catch (error) {
        console.error("API调用详细错误:", error);
        throw error;
      }
    },
  },
  beforeDestroy() {},
};
</script>

<style lang="scss" scoped>
.container {
  padding: 12px 16px;
  width: 100%;
  height: 100vh;
  overflow-y: auto;
  background-image: url("@/static/images/aiGuidance/ai-box-bg.png");
  background-size: 100% 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.initBox {
  padding: 100px 10px;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;

  .rectBox {
    width: 100%;
    height: 130px;
    position: relative;
    background: #edf5ff;
    border: 2px solid #ffffff;
    border-radius: 10px;
    box-shadow: 8px 2px 21px 10px rgba(201, 228, 255, 0.5);

    .rectRobot {
      width: 150px;
      height: 150px;
      position: absolute;
      right: -25px;
      top: -40px;
    }

    .rectContent {
      position: absolute;
      left: 20px;
      top: 20px;
      display: flex;
      color: #666666;
      flex-direction: column;
      font-size: 15px;
      width: 180px;

      .rectTitle {
        color: #0c326a;
        font-size: 16px;
        margin-bottom: 10px;
      }
    }
  }
}

.listBox {
  width: 100%;
  height: calc(100% - 110px);
  padding-top: 40px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;

  .listItem {
    width: 100%;

    margin-bottom: 20px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;

    &.end {
      align-items: flex-end;
    }

    .question {
      max-width: 85%;
      padding: 12px 20px;
      line-height: 25px;
      font-size: 16px;
      word-break: break-word;
      border-radius: 15px 5px 15px 15px;
      background-color: #3f81f1;
      color: #fff;
    }

    .answer {
      width: 100%;
      border-radius: 15px;
      background: linear-gradient(
          180deg,
          rgba(227, 235, 255, 1) 0%,
          rgba(252, 253, 255, 0) 100%
        ),
        rgba(245, 247, 255, 1);
      box-shadow: 5px 2px 15px 6px rgba(201, 228, 255, 0.5);

      display: flex;
      flex-direction: column;
      padding: 15px;
      font-size: 15px;
      font-weight: 400;
      letter-spacing: 0px;
      line-height: 22px;
      color: rgba(12, 50, 106, 1);
      text-align: left;
      vertical-align: top;

      .answerTitle {
        display: flex;
        font-size: 16px;
        font-weight: 500;
        letter-spacing: 0px;
        line-height: 23px;
        color: rgba(12, 50, 106, 1);
        text-align: left;
        vertical-align: top;
        margin-bottom: 5px;

        image {
          width: 20px;
          height: 18px;
          margin: 0 7px 0 2px;
        }
      }
      .searchBox {
        display: flex;
        .icon {
          width: 20px;
          height: 30px;
          margin-right: 10px;
          animation: searching 1.5s linear infinite;
        }
      }
      /* 旋转动画容器 */
      @keyframes searching {
        0% {
          transform: rotate(0deg) translateX(5px) rotate(0deg);
        }
        100% {
          transform: rotate(360deg) translateX(5px) rotate(-360deg);
        }
      }
      .animate-blink {
        width: 4px;
        height: 20px;
        animation: blink1 1.2s infinite steps(1, start);

        @keyframes blink1 {
          0%,
          100% {
            background: #000;
          }

          50% {
            background: transparent;
          }
        }
      }

      .pickerBox {
        display: flex;
        justify-content: space-between;
        height: 20px;
      }
      .gray {
        color: #8a8a8a;
      }
    }

    .answerCardBox {
      width: 100%;
      display: flex;
      margin-top: 20px;
      flex-wrap: wrap;
      gap: 10px;

      .answerCardItem {
        padding: 4px 15px;
        border-radius: 5px;
        background: rgba(255, 255, 255, 1);
        border: 1px solid #217aff;
        font-size: 15px;
        font-weight: 400;
        letter-spacing: 0px;
        line-height: 22px;
        color: rgba(12, 50, 106, 1);
        position: relative;
        overflow: hidden;
        .icon {
          width: 20px;
          height: 20px;
          position: absolute;
          bottom: -2px;
          right: -2px;
        }
      }
    }
  }
}

.modalList {
  margin-top: 10px;
  height: 30px;
  width: 100%;
  display: flex;
  gap: 10px;
  overflow-x: auto;

  .modalListItem {
    padding: 0 15px;
    border-radius: 5px;
    background: rgba(255, 255, 255, 1);
    font-size: 15px;
    font-weight: 400;
    letter-spacing: 0px;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 30px;

    color: rgba(12, 50, 106, 1);
    flex-shrink: 0;

    &.selected {
      border: 1px solid #007aff26;
      background: #dbeafe;
      color: #4d6bfe;
    }
  }
}

.search-footer {
  width: 100%;
  height: 46px;
  margin: 12px 0;
  border-radius: 25px;
  background: #ffffff;
  border: 1px solid #e4e6e8;
  position: relative;
  padding-right: 12px;
  display: flex;
  align-items: center;

  .input {
    width: calc(100% - 80px);
    height: 46px;
    line-height: 46px;
    margin-right: 30px;
    padding-left: 20px;
  }

  .button {
    height: 28px;
    width: 50px;
    font-size: 12px;
    line-height: 28px;
    padding: 0;
    text-align: center;
    border-radius: 14px;

    background: #dbeafe;
    color: #4d6bfe;
    margin: 0;

    &.disabled {
      background: #d6dee8;

      color: #fafafa;
    }

    &:after {
      display: none;
    }
  }
}
</style>
